iT邦幫忙

2022 iThome 鐵人賽

DAY 26
0
Software Development

持續進化論系列 第 26

DAY26 - 測試三部曲

  • 分享至 

  • xImage
  •  

當 API 開發完成後要給 Front-End 串接前還是要先測試一下功能是否正常,否則上線後才發現功能是不能使用的,那不是很糗嗎?這時可以利用瀏覽器直接 call API http://127.0.0.1:8000/api/categories ,此時就可以獲得心中預期的資料了。
https://ithelp.ithome.com.tw/upload/images/20220926/20115048HSZfMUNlhU.png
此時看一眼這種眼花撩亂的資料格式我都想下班了,那是不是有辦法可以讓系統幫我檢測格式是否正確呢?沒錯,這時候寫測試就可以派上用場了,以下就會開始介紹測試的作用及寫法。

首先常見的測試分為 Unit Test 及 Feature Test 兩種,Unit Test 會針對 Class 層級進行測試,但一般小專案因為商務邏輯相較簡單,通常除了金流、物流有一套共用套件以外較少對 Class 測試,較常用的是 Feature Test 整合性功能測試,以目前的功能就是來試試看 API 是否有回傳正確的資料格式。

在這之前要先為測試準備專用的測試資料庫,待開好新的資料庫命名為 dcat-testing 後為其準備專用 .env
cp .env .env.testing
修改設定

APP_ENV=testing
DB_DATABASE=dcat-testing

檢查 test 的設定檔 phpunit.xml

 <server name="APP_ENV" value="testing"/>

value 要與 .env.testing 的 APP_ENV 對應到才會正確使用設定

先為新的資料庫設定 migration
php artisan migration —env=testing

到此準備工作結束,接下來就可以開始為 Category Index 這隻 API 撰寫測試了
php artisan make:test Category/IndexTest
要注意所有測試檔案的後綴都要是 Test 才會被系統認定為測試檔案

RefreshDatabase & DatabaseTransactions
建立好測試檔案後即可看到 use Illuminate\Foundation\Testing\RefreshDatabase , 麻煩將其變更為 use Illuminate\Foundation\Testing\DatabaseTransactions , 並在 Class 的裡面使用這個 trait , use DatabaseTransactions

原因在於每當測試完畢時 RefreshDatabase 會將全部的 Table rollback 在進行 migrate,而 DatabaseTransactions 只會將此次測試所新增的資料 rollback 而已,當測試越來越多時所花的時間就會有很大的差別,敝司有一個裝案將全部的 RefreshDatabase 改為 DatabaseTransactions 測試時間從 2 小時縮減到 15分鐘,可見其差別有多大。

終於可以來到正題了,所謂測試三部曲為:假資料、 call API、 assert

假資料的部分可以使用 DAY16 準備好的 Factory 來完成,並利用 sync 來完成關聯

$categories = Category::factory(3)->create();
$products = Product::factory(3)->create();

foreach ($products as $product) {
    $characteristics = Characteristic::factory(2)->create();
    $actors = Actor::factory(2)->create();
    $video = Video::factory(2)->create([
        'product_id' => $product->id,
    ]);

    $product->characteristics()->sync($characteristics->pluck('id'));
    $product->actors()->sync($actors->pluck('id'));
}

$categories[0]->products()->sync($products->pluck('id'));
$categories[1]->products()->sync([
    $products[0]->id,
    $products[1]->id,
]);
$categories[2]->products()->sync([
    $products[1]->id,
    $products[2]->id,
]);

Call API,並利用 dump 來觀察 API 資料

$response = $this->json('GET', '/api/categories');
$response->dump();

assertStatus 及 assertJsonStructure 是我常用的兩個斷言,使用 * 代表以下的 array 都得符合該格式

$response->assertStatus(200)
    ->assertJsonStructure([
        '*' => [
            'id',
            'name',
            'products' => [
                '*' => [
                    'id',
                    'name',
                    'type',
                    'outline',
                    'videos' => [
                        '*' => [
                            'id',
                            'path',
                            'previously',
                        ]
                    ],
                    'characteristics' => [
                        '*' => [
                            'id',
                            'name',
                        ]
                    ],
                    'actors' => [
                        '*' => [
                            'id',
                            'name',
                        ]
                    ],
                ]
            ],
        ]
    ]);

完成之後就可以下指令來測試 API 是否正確了
vendor/bin/phpunit --filter='Category'
https://ithelp.ithome.com.tw/upload/images/20220926/20115048aZuIXdnpFv.png
如此一來就有最基礎的測試案例了,有時會因為後續的開發會動到重複使用的 Class 而造成舊功能失效時,只要能在上線前跑一次測試及早發現錯誤就可避免線上功能失效,這就是測試的強大所在。一年前的鐵人賽也花了一個篇章來寫關於測試,今年也是如此,這應該代表測試在我心中及一年來的職場經歷中還是很重要的吧。


上一篇
DAY25 - API架構
下一篇
DAY27 - 細節藏在魔鬼裡
系列文
持續進化論30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言